﻿using AutoMapper;
using ProjectManageSystemApi.DbEntity;
using ProjectManageSystemApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;

namespace ProjectManageSystemApi.Services.Impl
{
    public class UserCheckInfoService : IUserCheckInfoService
    {
        readonly IFreeSql _fsql;
        readonly IMapper _mapper;
        public UserCheckInfoService(IFreeSql fsql, IMapper mapper)
        {
            _mapper = mapper;
            _fsql = fsql;
        }

        /// <summary>
        /// 人员上班打卡
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool UserClockIn(UserClockInRequest data)
        {
            return _fsql.Update<UserCheckInfo>(data.UserCheckInfoId)
                .Set(x=>x.ClockInDate, DateTime.Now)
                .Set(x=>x.ClockInPicUrl, data.PicUrl)
                .ExecuteAffrows() > 0;
        }

        /// <summary>
        /// 人员下班打卡
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool UserClockOut(UserClockInRequest data)
        {
            return _fsql.Update<UserCheckInfo>(data.UserCheckInfoId)
                .Set(x => x.ClockOutDate, DateTime.Now)
                .Set(x => x.ClockOutPicUrl, data.PicUrl)
                .ExecuteAffrows() > 0;
        }

        /// <summary>
        /// 判断是否已经打过上班卡
        /// </summary>
        public bool ExistUserClockIn(long UserId, DateTime date)
        {
            return _fsql.Select<UserCheckInfo>().Any(x => x.UserId == UserId && x.BelongsDate == date && x.ClockInDate != null);
        }

        /// <summary>
        /// 判断是否已经打过下班卡
        /// </summary>
        public bool ExistUserClockOut(long UserId, DateTime date)
        {
            return _fsql.Select<UserCheckInfo>().Any(x => x.UserId == UserId && x.BelongsDate == date && x.ClockOutDate != null);
        }

        /// <summary>
        /// 通过用户信息
        /// </summary>
        /// <returns></returns>
        public List<UserCheckDto> GetUserCheckInfoByMonth(long userId, DateTime startTime, DateTime endTime)
        {
            var data = _fsql.Select<UserCheckInfo>()
                .IncludeMany(x => x.Details)
                .Where(x => x.UserId == userId && x.BelongsDate >= startTime && x.BelongsDate < endTime)
                .ToList();
            return _mapper.Map<List<UserCheckDto>>(data);
        }


        public PageVo<IEnumerable<UserCheckInfoDto>> GetAllUserCheckInfo(PageBo<UserCheckInfoParams> pageBo) 
        {
            long total = 0;
            var userIds = _fsql.Select<UserCheckInfo>()
                .Where(x => x.BelongsDate >= pageBo.Param.StartDate && x.BelongsDate <= pageBo.Param.EndDate)
                .GroupBy(x => x.UserId)
                .Page(pageBo.Page, pageBo.Size);
            var data = _fsql.Select<UserCheckInfo>()
                .Include(x=> x.UserInfo)
                .IncludeMany(x => x.Details)
                .IncludeMany(x=>x.Details, then => then.Include(t => t.WorkerTypeInfo))
                .Where(x => x.BelongsDate >= pageBo.Param.StartDate && x.BelongsDate <= pageBo.Param.EndDate);
            if (pageBo.Param.UserId.HasValue && pageBo.Param.UserId.Value > 0)
            {
                data = data.Where(x => x.UserId == pageBo.Param.UserId.Value);
                total = 0;
            }
            else 
            {
                total = userIds.Count();
                userIds = userIds.Page(pageBo.Page, pageBo.Size);
                var userIdDatas = userIds.ToList(u => u.Key);
                data = data.Where(x => userIdDatas.Contains(x.UserId));
            }

            var resultData = data.ToList(x => new UserCheckSqlDto
            {
                UserCheckInfo = x,
                Details = x.Details,
                UserName = x.UserInfo.UserName,
                Roles = string.Join(",",
                    _fsql.Select<SysCoreRole>().Where(r =>
                        _fsql.Select<SysCoreUserRoleLink>().Where(y => y.UserId == x.UserId).ToList(l => l.RoleId).Contains(r.Id)
                    ).ToList(d => d.Name))
            });
            var result = from r in resultData
                         group r by r.UserCheckInfo.UserId into d
                         let f = d.First()
                         let l = d.ToList()
                         select new UserCheckInfoDto
                         {
                             UserId = d.Key,
                             UserName = f.UserName,
                             Roles = f.Roles,
                             TotalCount = l.Count,
                             CheckCount = l.Count(x=> x.UserCheckInfo.ClockInDate.HasValue) + l.Count(x=> x.UserCheckInfo.ClockOutDate.HasValue),
                             UserCheckData = l.OrderByDescending(y => y.UserCheckInfo.BelongsDate).Select(s => _mapper.Map<UserCheckDto>(s))
                         };

            return new PageVo<IEnumerable<UserCheckInfoDto>>()
            {
                Page = pageBo.Page,
                Size = pageBo.Size,
                Total = total,
                Datas = result
            };
        }

        public uint GetIdByUserIdAndBelongsDate(long userId, DateTime belongsDate) 
        {
            var data = _fsql.Select<UserCheckInfo>().Where(x => x.UserId == userId && x.BelongsDate == belongsDate.Date).ToOne();
            if (data != null) 
            {
                return data.Id;
            }
            UserCheckInfo info = new UserCheckInfo
            {
                UserId = userId,
                BelongsDate = belongsDate.Date
            };
            return (uint)_fsql.Insert(info).ExecuteIdentity();
        }
    }
}
